from .models import UserProfile,TempGroup,Template,FieldType,TempField,EnumValue,FileTable,ImageTable,ProFLow,\
FlowTask,FlowInst,SubTask,SubTaskAttach,ProEvent,EventAttach
from .models import Instance,ShortTable,LongTable,IntTable,FloatTable,BoolTable,EnumTable,DateTable,ListTable
from .serializers import UserSeri,TempGroupSeri,TemplateWriteSeri,TemplateReadSeri,FieldTypeSeri,TempFieldSeri
from .serializers import InstanceSeri,ProFlowSeri,FlowTaskSeri,FlowInstSeri,SubTaskSeri,SubTaskAttachSeri,\
ProEventSeri,EventAttachSeri
from .baseauthentication import MyAuthentication

from rest_framework import viewsets
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from django.db.models import Count

import datetime
import os

class LoginVW(APIView):
    '''
    basic认证, 如果认证失败浏览器会弹出登录框,所以不使用
    登录成功,返回token, 菜单数据
    '''
    authentication_classes = [MyAuthentication]
    
    def gen_route(self):
        '''
        主要是返回人员模版, 项目模版
        '''
        route_dicts = {
            'employee':[],
            'project': []
            }
        queryset = Template.objects.filter(enabled=True)
        for qst in queryset:
            if qst.group.type == '项目':
                route_dicts['project'].append({'name':qst.en_name,'id':qst.id,'ch_name':qst.ch_name})
            else:
                route_dicts['employee'].append({'name':qst.en_name,'id':qst.id,'ch_name':qst.ch_name})
        return route_dicts
    
    def post(self,request):
        tokenobj = Token.objects.filter(user_id=request.user.id).first()
        if not tokenobj:
            tokenobj = Token.objects.create(user=request.user)
        token = tokenobj.key
        menu = self.gen_route()
        return Response({'token':token,'superuser':request.user.is_superuser,'menu':menu})
    
class UserVS(viewsets.ModelViewSet):
    queryset = UserProfile.objects.all()
    serializer_class = UserSeri
    
class TempGroupVS(viewsets.ModelViewSet):
    queryset = TempGroup.objects.all()
    serializer_class = TempGroupSeri
    
    def get_queryset(self):
        '''
        重写get_queryset方法, 支持接收get 参数,过滤queryset
        '''
        queryset = TempGroup.objects.all()
        query_dict = {}
        for key in self.request.query_params.keys():
            value=self.request.query_params.get(key,None)
            if value is not None:
                query_dict[key]=value

        queryset = queryset.filter(**query_dict)
        return queryset
    
    def list(self, request, *args, **kwargs):
        '''
        返回组下的模版数
        '''
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        datas = serializer.data
        for data in datas:
            data['templates'] = len(Template.objects.filter(group_id=data['id']))
        return Response(datas)

class TemplateVS(viewsets.ModelViewSet):
    queryset = Template.objects.all()
    serializer_class = TemplateReadSeri
    
    def get_serializer_class(self):
        method = self.request.method
        if method == 'PUT' or method == 'POST':
            return TemplateWriteSeri
        else:
            return TemplateReadSeri
        
    def group_by(self,group_key,datas):
        data_dict = {}
        key_list = group_key.split('.')
        for data in datas:
            if len(key_list) == 2:
                key = data[key_list[0]][key_list[1]]
            else:
                key = data.get(group_key)
            
            if not data_dict.get(key):
                data_dict[key] = []
            data_dict[key].append(data)
              
        return data_dict
        
        
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        data = serializer.data
        '''
        支持group_by参数, 如?group_by=group.type 按照外键group的类型分组
        '''
        group_key = self.request.query_params.get('group_by',None)
        if group_key:
            data = self.group_by(group_key, data)
                
        return Response(data)

class FieldTypeVS(viewsets.ModelViewSet):
    queryset = FieldType.objects.all()
    serializer_class = FieldTypeSeri

class TempFieldVS(viewsets.ModelViewSet):
    queryset = TempField.objects.all()
    serializer_class = TempFieldSeri
    
    def get_queryset(self):
        '''
        重写get_queryset方法, 支持接收get 参数,过滤queryset
        '''
        queryset = TempField.objects.all().order_by('order')
        query_dict = {}
        for key in self.request.query_params.keys():
            value=self.request.query_params.get(key,None)
            if value is not None:
                query_dict[key]=value

        queryset = queryset.filter(**query_dict)
        return queryset
    
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        datas = []
        for data in serializer.data:
            if data.get('type_name') == '枚举':
                data['field_type']=[]
                for ev in EnumValue.objects.filter(field_id=data.get('id')).values('key','value'):
                    data['field_type'].append({'key':ev['key'],'value':ev['value']})
            datas.append(data)
        
        return Response(datas)
    
    def create(self, request, *args, **kwargs):
        """
        重写create, 当字段类型是枚举时, 需要把枚举key,value存到EnumValue 表
        """
        data = request.data
        serializer = self.get_serializer(data=data)
        
        serializer.is_valid()
        self.perform_create(serializer)
        if serializer.errors:
            return Response({'status':False,'message':serializer.errors})
        else:
            status = True
            message = None
            if serializer.data['type_name'] == '枚举':
                self.save_enum('create',data) #模型字段先保存, 枚举key,value存储依赖 field ID
            
        return Response({'status':status,'message':message})
    
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=False)
        if serializer.errors:
            return Response({'status':False,'message':serializer.errors})
        
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}
            
        if serializer.data['type_name'] == '枚举':
            self.save_enum('update', request.data)
            
        return Response({'status':True,'message':serializer.data})
    
    def save_enum(self,action,data):
        field = TempField.objects.get(en_name=data['en_name'])
        '''
        字段虽然是编辑, 但是对于枚举项来说有可能包含新增, 有可能删除, 所以直接删除旧的, 批量添加新的
        '''
        EnumValue.objects.filter(field=field).delete()
        
        enum_value_list = []
        for key in data['enums_key']:
            obj = EnumValue(field=field,key=data['enums_key'][key],value=data['enums_value'][key])
            enum_value_list.append(obj)
        EnumValue.objects.bulk_create(enum_value_list)

class InstanceVS(viewsets.ModelViewSet):
    queryset = Instance.objects.all()
    serializer_class = InstanceSeri
    '''
    定义分页类全局设置
    '''
    page_size = 10 #默认每页显示5条数据
    page_query_param = "page" #指定查询第几页的 查询参数
    page_size_query_param = "page_size" #指定每页显示多少条数据的参数
    max_page_size = 20 # 每页最大显示的条数
    '''
    资产实例添加流程
    1 从post 数据中取出 model_id, 属于的模型
    2 从ModelField 中查出此模型所有的字段(必填项, 一般项)
    3 校验数据,包括 a)必填项, b)数据类型--整型，布尔等, c)数据格式--数据组合
    4 全部验证通过,写入实例表Instance (输入:模型ID, 返回:实例ID)
    5 数据相应的表, 如int类型的写入IntTable (输入:实例ID,字段ID,值)
    6 结果处理, 如果失败(从实例表Instance删除实例,已经写入各值的表数据会自动删除, 返回失败原因), 成功(返回成功)
    
    资产实例列表获取流程
    1 从query_params 中取出model_id
    2 从Instance中找出属于 model_id 的 实例
    3 取出每个实例所有字段的值, 组成dict, 放到 list 供返回
    注：只获取需要显示的字段的值
    '''
    #数据类型判断
    type_dict = {
        'short':str,
        'long':str,
        'int':int,
        'float':float,
        'bool':bool,
        'enum':str,
        'datetime':datetime,
        'list': list
        }
    model_dict = {
        'short': ShortTable,
        'long': LongTable,
        'int': IntTable,
        'float': FloatTable,
        'bool': BoolTable,
        'enum': EnumTable,
        'datetime': DateTable,
        'file': FileTable,
        'image': ImageTable,
        'list': ListTable
        }
    
    
    def get_queryset(self):
        '''
        重写get_queryset方法, 支持接收get 参数,过滤queryset
        并且要支持分页, 需要过滤出 query_params : page page_size, 所以要避免与表字段冲突
        '''
        queryset = Instance.objects.all()
        query_dict = {}
        for key in self.request.query_params.keys():
            '''
            过滤页查询参数关键字
            '''
            if key in [self.page_query_param,self.page_size_query_param]:
                pass
            else:
                value=self.request.query_params.get(key,None)
                if value is not None:
                    query_dict[key]=value   
        '''
        先条件查询,再根据页查询条件显示数据
        性能问题: 每次请求都会查询条件, 然后取指定条数据, 这里可以把第一次条件过滤后的对象保存,
                当同一个session进行上一页,下一页的时候就可以避免 查询过滤这个动作.
        '''        
        queryset = queryset.filter(**query_dict)
        
        '''
        获取页号, 每页数据size
        
        temp_page = 1 #默认第一页
        temp_page_size = self.page_size #每页默认5条
        for key in self.request.query_params.keys():
            if key in [self.page_query_param,self.page_size_query_param]:
                value=self.request.query_params.get(key,None)
                if value is not None:
                    if key == self.page_query_param:
                        temp_page = value
                    else:
                        temp_page_size = value
        
        
        根据页号，页大小 计算显示的数据, 如page=2 , page_size=10, 那么 start_index = (page-1)*page_size, end_index = page*page_size
        
        start_index = (int(temp_page) -1 ) * int(temp_page_size)
        end_index =  int(temp_page) * int(temp_page_size)
        return queryset[start_index:end_index]
        '''
        return queryset
    
    def update(self, request, *args, **kwargs):
        data = request.data
        self.validate_results = {'status':[],'errors':[]}
        #从ModelField 中查出此模型所有的字段(必填项, 一般项)
        template_id = data['template']
        fields_obj = TempField.objects.filter(template=template_id)
        total_fields_obj = [obj for obj in fields_obj]
        
        must_fields_obj = [ obj for obj in total_fields_obj if obj.must]
        #验证
        data = self.validate_data_must(must_fields_obj,data)
        data = self.validate_data_type(total_fields_obj,data)
        if sum(self.validate_results['status']) == len(self.validate_results['status']):
            self.instance_update(kwargs['pk'])
            self.value_update(kwargs['pk'], total_fields_obj,data)
            return Response({'status':True})
        else:
            return Response({'status':False,'error':self.validate_results['errors']})

    def retrieve(self, request, *args, **kwargs):
        inst_id = kwargs['pk']
        inst_obj = Instance.objects.get(id=inst_id)
        fields_obj = TempField.objects.filter(template=inst_obj.template)
        total_fields_obj = [obj for obj in fields_obj]
            
        data = self.get_instance_value(inst_obj.id, total_fields_obj)
        data['template'] = inst_obj.template.id
        data['create_time'] = inst_obj.create_time
        return Response({'status':True,'data':data})
    
    def list(self,request,*args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        inst_list = []
            
        for inst in queryset:
            temp_obj = Template.objects.get(id=inst.template.id)
            fields_obj = TempField.objects.filter(template=inst.template)
            total_fields_obj = [obj for obj in fields_obj]
            
            data = self.get_instance_value(inst.id, total_fields_obj)
            data['template'] = inst.template.id
            data['create_time'] = inst.create_time
            data['template_name'] = inst.template.ch_name
            data['template_type'] = temp_obj.group.ch_name
            inst_list.append(data)
            
        return Response({'status':True,'data':inst_list})
    
    def get_instance_value(self,inst_id,fields_obj):
        inst_dict = {'id':inst_id}
        for field_obj in fields_obj:
            field_name = field_obj.en_name
            field_type = field_obj.type.en_name
            objs = self.model_dict[field_type].objects.filter(instance_id=inst_id,field=field_obj.en_name)
            if objs:
                if field_type in ['file','image']:
                    field_value = [{'name':obj.value.name.split('/')[1],'url':obj.value.url} for obj in objs]
                elif field_type in ['list']:
                    field_value = objs[0].value.split(',')
                else:
                    field_value = objs[0].value
            else:
                field_value = None
            inst_dict[field_name] = field_value
            
        return inst_dict
    
    
    def validate_data(self,data,total_fields_obj):
        '''
        执行数据检查
        '''
        must_fields_obj = [ obj for obj in total_fields_obj if obj.must]
        #验证
        data = self.validate_data_must(must_fields_obj,data)
        data = self.validate_data_type(total_fields_obj,data)
        return data
        
    
    def create(self, request, *args, **kwargs):
        data = request.data
        self.validate_results = {'status':[],'errors':[]}
        
        template_id = data['template']
        fields_obj = TempField.objects.filter(template=template_id)
        total_fields_obj = [obj for obj in fields_obj]
        
        
        data = self.validate_data(data,total_fields_obj)
        if sum(self.validate_results['status']) == len(self.validate_results['status']):
            inst_id = self.instance_save(data['template'], request.user.id)
            self.value_save(inst_id, total_fields_obj,data)
            
            return Response({'status':True})
        else:
            return Response({'status':False,'error':self.validate_results['errors']})
    
    def validate_data_must(self,fields_obj,data):
        #必填项验证
        for field_obj in fields_obj:
            if field_obj.en_name in data:
                if data[field_obj.en_name] is None:
                    self.validate_results['status'].append(0)
                    self.validate_results['errors'].append('{} 值不能为空'.format(field_obj.field_name))
                    del data[field_obj.en_name]#防止validate_data_type出错
            else:
                self.validate_results['status'].append(0)
                self.validate_results['errors'].append('{} 不存在'.format(field_obj.field_name))
        return data
    
    def validate_data_type(self,fields_obj,data):
        #1 使用fields_obj 字段去 datas匹配，而不是datas里的key去 fields_obj匹配
        for field_obj in fields_obj:
            if field_obj.en_name in data:
                data_value = data[field_obj.en_name]
                data_type = field_obj.type.en_name
                if data_type in ['file','image']:
                    '''
                    当项目编辑时, 会有image,file字段,需要删除
                    '''
                    del data[field_obj.en_name]
                elif data_value is not None: #这里只判断有值的, 不必须填的可能没有值
                    if data_type == 'datetime':
                        data_value = self.gmt_to_localtime(data_value)
                        data[field_obj.en_name] = data_value
                        self.validate_results['status'].append(1)
                    elif data_type == 'list':
                        data[field_obj.en_name] = ','.join(data_value)
                        self.validate_results['status'].append(1)
                    elif data_type == 'int':#前端有一个问题, input 的 type='number'不生效, 所以后端需要尝试进行类型转换, 主要是整型
                        try:
                            data_value = int(data_value)
                            #更新数据值
                            data[field_obj.en_name] = data_value
                        except:
                            self.validate_results['status'].append(0)
                            self.validate_results['errors'].append('字段{}值为{},不是 {}类型'.format(field_obj.en_name,
                                                                                         data_value,
                                                                                         self.type_dict[data_type]))
                            continue
                        else:
                            self.validate_results['status'].append(1)
                    elif not isinstance(data_value, self.type_dict[data_type]):
                        self.validate_results['status'].append(0)
                        self.validate_results['errors'].append('字段{}值为{},不是 {}类型'.format(field_obj.en_name,
                                                                                         data_value,
                                                                                         self.type_dict[data_type]))
                    else:
                        self.validate_results['status'].append(1)
                else:
                    del data[field_obj.en_name]#删除值为空的字段,防止写入数据库出错
        return data
        
    def instance_update(self,inst_id):
        Instance.objects.filter(id=inst_id).update()
    
    def instance_save(self,model_id,owner_id):
        #数据写入Instance
        obj = Instance.objects.create(template_id=model_id,owner_id=owner_id)
        return obj.id
    
    def value_update(self,inst_id,fields_obj,data):
        '''
        根value_save类似操作, 不过要考虑字段才新增
        '''
        
        for field_obj in fields_obj:
            if field_obj.en_name in data:
                data_value = data[field_obj.en_name]
                data_type = field_obj.type.en_name
                obj = self.model_dict[data_type].objects.filter(**{'instance_id':inst_id,
                                                                'field':field_obj.en_name})
                #如果是新增字段, obj查出来是空
                if obj:
                    obj.update(value=data_value)
                else:
                    self.model_dict[data_type].objects.create(**{'instance_id':inst_id,
                                                        'field':field_obj.en_name,
                                                        'value':data_value})

    
    def value_save(self,inst_id,total_fields_obj,data):
        '''
        实际数据写入对应表
        ShortTable, LongTable, IntTable, FloatTable, BoolTable, DateTable, TimeTable, EnumTable
        目前枚举只支持值为字符串, 如果要支持不同类型的, 需要设置enum_id(相当于字段名),id,value存入相应表
        '''
        
        for field_obj in total_fields_obj:
            if field_obj.en_name in data:
                data_value = data[field_obj.en_name]
                data_type = field_obj.type.en_name
                try:
                    self.model_dict[data_type].objects.create(**{'instance_id':inst_id,
                                                            'field':field_obj.en_name,
                                                            'value':data_value})
                except Exception as e:
                    print('eeeeee',e)
                    Instance.objects.get(id=inst_id).delete()
    
    def gmt_to_localtime(self,timestr):
        '''
        前端vue-datepicker-local 插件使用的是gmt时间, 需要转成北京时间
        1 需要正则判断, 正确的时间不转换
        '''
        UTC_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
        try:
            utcTime = datetime.datetime.strptime(timestr, UTC_FORMAT)
        except:
            return timestr
        localtime = utcTime + datetime.timedelta(hours=8)
        return localtime

class InstSearch(APIView):
    '''
    1 获取字段类型
    第一轮搜索: 
      用第一个key 的value 去获取所有满足的 instance id 并 放入instances
      
    第二轮搜索:
      用第二个key 的value + 每一个instance id 去搜索, 把满足的 instance 放入 instances
    
    直到所有key 的 value 被搜索完, 得到最终满足所有条件的 instances
    
    最后: 获取实例数据返回
    
    '''
    model_dict = {
        'short':ShortTable,
        'long':LongTable,
        'int':IntTable,
        'float':FloatTable,
        'bool':BoolTable,
        'enum':EnumTable,
        'datetime':DateTable,
        'file': FileTable,
        'image': ImageTable,
        'list': ListTable
    }
    
    def get_instance_value(self,inst_id,fields_obj):
        inst_dict = {'id':inst_id}
        for field_obj in fields_obj:
            field_name = field_obj.en_name
            field_type = field_obj.type.en_name
            objs = self.model_dict[field_type].objects.filter(instance_id=inst_id,field=field_obj.en_name)
            if objs:
                if field_type in ['file','image']:
                    field_value = [{'name':obj.value.name.split('/')[1],'url':obj.value.url} for obj in objs]
                elif field_type in ['list']:
                    field_value = objs[0].value.split(',')
                else:
                    field_value = objs[0].value
            else:
                field_value = None
            inst_dict[field_name] = field_value
            
        return inst_dict
    
    def remove_null(self,search):
        tmp_search = {}
        for key in search.keys():
            if search[key] is None:
                continue
            if isinstance(search[key], list) or len(search[key].strip()) != 0:
                tmp_search[key] = search[key]
        return tmp_search
    
    def distinct_for_inst_id(self,v_insts):
        '''
        v_insts 是 LongTable,ShortTable等 存值的实例, 需要根据 instance id去重, 特别是FileTable和ImageTable,
        因为一个实例的一个项(如项目的合同文件这个字段, 文件可能上传多个)
        '''
        datas = {}
        for v_inst in v_insts:
            datas[v_inst.instance.id] = v_inst
        
        return [val for val in datas.values()]
        
    def search_for_datetime(self,field_obj,key,s_value,inst=None):
        #如果字段类型是时间,不能使用contains
        start_time = gmt_to_localtime(s_value[0])
        end_time = gmt_to_localtime(s_value[1])
        if inst:
            insts = self.model_dict[field_obj.type.en_name].objects.filter(instance=inst.instance,
                                                                           field=key,
                                                                           value__range=(start_time,end_time))
        else:
            insts = self.model_dict[field_obj.type.en_name].objects.filter(field=key,
                                                                           value__range=(start_time,end_time))
        return insts
    
    def search_for_str(self,field_obj,key,s_value,inst=None):
        if inst:
            insts = self.model_dict[field_obj.type.en_name].objects.filter(instance=inst.instance,
                                                                           field=key,
                                                                           value__contains=s_value)
        else:
            insts = self.model_dict[field_obj.type.en_name].objects.filter(field=key,
                                                                           value__contains=s_value)
        return self.distinct_for_inst_id(insts)
    
    def post(self,request):
        insts = []
        datas = []
        template = request.data['template']
        search = self.remove_null(request.data['search'])
        
        if not search:#如果没有搜索key, 返回对应模版的所有实例, 这里的insts 是 Instance
            insts = Instance.objects.filter(template=template)
            
            for inst in insts:
                fields_obj = TempField.objects.filter(template=inst.template)
                data = self.get_instance_value(inst.id, fields_obj)
                datas.append(data)
            return Response(datas)
        
        #这里的insts 是LongTable, ShortTable这些实例
        for key in search.keys():
            s_value = search[key]
            field_obj = TempField.objects.get(template_id=template,en_name=key)
            #如果字段类型是时间,不能使用contains
            if field_obj.type.en_name == 'datetime':
                insts = self.search_for_datetime(field_obj, key, s_value)
            else:
                insts = self.search_for_str(field_obj, key, s_value)
            
            if insts:
                tmp_insts = []
                for inst in insts:
                    if field_obj.type.en_name == 'datetime':
                        t_inst = self.search_for_datetime(field_obj, key, s_value, inst)
                    else:
                        t_inst = self.search_for_str(field_obj, key, s_value, inst)
                    if t_inst:
                        tmp_insts.append(t_inst[0])
                insts = tmp_insts
            else:
                return Response([])
                
        for inst in insts:
            fields_obj = TempField.objects.filter(template=inst.instance.template)
            data = self.get_instance_value(inst.instance.id, fields_obj)
            datas.append(data)
        
        return Response(datas)
    
class InstUpload(APIView):
    model_dict = {
        'file': FileTable,
        'image': ImageTable
        }
    def post(self,request):
        instance_id = request.data.get('instance')
        field_type_id = request.data.get('field_type')
        field_en_name = request.data.get('field_en_name')
        field_type = FieldType.objects.get(id=field_type_id).en_name
        files = request.FILES.get('file')
        obj = self.model_dict[field_type].objects.create(instance_id=instance_id,
                                                         field=field_en_name,
                                                         value=files)
        return Response({'id':obj.id})
    
    def get(self,request):
        inst_id = request.query_params.get('instance')
        inst_obj = Instance.objects.get(id=inst_id)
        temp_field_obj = TempField.objects.filter(template=inst_obj.template)
        data = {}
        for obj in temp_field_obj:
            if obj.type.en_name in ['file','image']:
                #从存储值的表中取出对象
                v_objs = self.model_dict[obj.type.en_name].objects.filter(instance_id=inst_id,field=obj.en_name)
                data[obj.en_name] = []
                if v_objs:
                    data[obj.en_name] = [{'id':obj.id,
                                          'name':obj.value.name.split('/')[1],
                                          'url':obj.value.url} for obj in v_objs]
        return Response(data)
    
    def delete_file_from_disk(self,filename):
        fullname = os.path.join('media',filename)
        if os.path.isfile(fullname):
            os.remove(fullname)
    
    def delete(self, request, *args, **kwargs):
        try:
            field_type = request.query_params.get('type')
            v_inst_id = kwargs['id']
            obj = self.model_dict[field_type].objects.get(id=v_inst_id)
            self.delete_file_from_disk(obj.value.name)
            obj.delete()
        except Exception as e:
            return Response({'status':False,'data':str(e)})
        return Response({'status':True})
    
def gmt_to_localtime(timestr):
        '''
        前端vue-datepicker-local 插件使用的是gmt时间, 需要转成北京时间
        1 需要正则判断, 正确的时间不转换
        '''
        UTC_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
        try:
            utcTime = datetime.datetime.strptime(timestr, UTC_FORMAT)
        except:
            return timestr
        localtime = utcTime + datetime.timedelta(hours=8)
        return localtime

flow_status = {
    'wait': {'text':'等待进行', 'color': '#ddd'},
    'run': {'text':'正在进行', 'color': '#409EFF'},
    'finish': {'text':'已经完成', 'color': '#67C23A'}
    }

class ProFlowVS(viewsets.ModelViewSet):
    queryset = ProFLow.objects.all()
    serializer_class = ProFlowSeri
    
    def get_queryset(self):
        '''
        重写get_queryset方法, 支持接收get 参数,过滤queryset
        '''
        queryset = ProFLow.objects.all().order_by('order')
        query_dict = {}
        for key in self.request.query_params.keys():
            value=self.request.query_params.get(key,None)
            if value is not None:
                query_dict[key]=value

        queryset = queryset.filter(**query_dict)
        return queryset
    
    def query_flow(self):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return serializer.data
    
    def query_task(self,flow):
        queryset = FlowTask.objects.filter(flow=flow)
        serializer = FlowTaskSeri(queryset,many=True)
        return serializer.data
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=False)
        if serializer.errors:
            return Response({'status':False,'data':serializer.errors})
        self.perform_create(serializer)
        
        return Response({'status':True, 'data':serializer.data})
    
    def list(self, request, *args, **kwargs):
        flow_datas = self.query_flow()
        for flow_data in flow_datas:
            task_datas = self.query_task(flow_data['id'])
            flow_data['steps'] = task_datas
            try:
                flowinst_obj = FlowInst.objects.get(flow=flow_data['id'])
            except:
                flow_data['status'] = flow_status['wait']
            else:
                flow_data['status'] = flow_status[flowinst_obj.status]
        return Response(flow_datas)

'''
模版下的流程的任务视图
'''
class FlowTaskVS(viewsets.ModelViewSet):
    queryset = FlowTask.objects.all().order_by('order')
    serializer_class = FlowTaskSeri
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=False)
        if serializer.errors:
            return Response({'status':False,'data':serializer.errors})
        self.perform_create(serializer)
        
        return Response({'status':True, 'data':serializer.data})
    

'''
流程实例视图
'''
class FlowInstVS(viewsets.ModelViewSet):
    queryset = FlowInst.objects.all()
    serializer_class = FlowInstSeri
    
    def get_queryset(self):
        '''
        重写get_queryset方法, 支持接收get 参数,过滤queryset
        '''
        queryset = FlowInst.objects.all()
        query_dict = {}
        for key in self.request.query_params.keys():
            value=self.request.query_params.get(key,None)
            if value is not None:
                query_dict[key]=value

        queryset = queryset.filter(**query_dict)
        return queryset
    
    def gen_inst_data(self,project_id,flows):
        datas = []
        for flow in flows:
            date_range = flow.get('date_range')
            if not date_range:
                return {'status':False,'data':'{} 时间未设置'.format(flow['ch_name'])}
            data = {
                'instance': project_id,
                'template':flow['template'],
                'flow': flow['id'],
                'begin_date': flow['date_range'][0],
                'end_date': flow['date_range'][1],
                'duration': flow['duration'],
                'to_start': float(flow['to_start']),
                'status': flow['status']
                }
            datas.append(data)
        return {'status':True,'data':datas}
    
    def create(self, request, *args, **kwargs):
        flows = request.data.get('flows')
        project_id = request.data.get('project')
        res = self.gen_inst_data(project_id,flows)
        if not res['status']:
            return Response({'status':False,'data':res['data']})
        for data in res['data']:
            serializer = self.get_serializer(data=data)
            serializer.is_valid(raise_exception=False)
            if serializer.errors:
                return Response({'status':False,'data':serializer.errors})
            else:
                self.perform_create(serializer)
        return Response({'status':True}, status=201)
    
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        
        '''
        把实例的子任务获取添加上
        '''
        datas = serializer.data
        for flow_inst in datas:
            pro_flow_id = flow_inst['flow']
            flow_task_queryset = FlowTask.objects.filter(flow=pro_flow_id).order_by('order')
            flow_task_serializer = FlowTaskSeri(flow_task_queryset, many=True)
            flow_tasks = flow_task_serializer.data
            flow_inst['tasks'] = flow_tasks
            #flow_inst['status'] = flow_status[flow_inst['status']]
            for flow_task in flow_tasks:
                sub_task_queryset = SubTask.objects.filter(task=flow_task['id'])
                sub_task_serializer = SubTaskSeri(sub_task_queryset, many=True)
                #把member转成list
                subtasks = sub_task_serializer.data
                for subtask in subtasks:
                    subtask['member'] = subtask['member'].split(',')
                    attach_queryset = SubTaskAttach.objects.filter(task=subtask['id'])
                    subtask['attach'] = [{'id':obj.id,
                                          'name':obj.attach.name.split('/')[1],
                                          'url':obj.attach.url} for obj in attach_queryset]
                flow_task['subtasks'] = subtasks
        return Response({'status':True,'data':datas})

'''
FlowTask的子任务视图
'''
class SubTaskVS(viewsets.ModelViewSet):
    queryset = SubTask.objects.all()
    serializer_class = SubTaskSeri
    
    def get_queryset(self):
        '''
        重写get_queryset方法, 支持接收get 参数,过滤queryset
        '''
        queryset = SubTask.objects.all()
        query_dict = {}
        for key in self.request.query_params.keys():
            value=self.request.query_params.get(key,None)
            if value is not None:
                query_dict[key]=value

        queryset = queryset.filter(**query_dict)
        return queryset
    
    def format_data(self,data):
        data['begin_date'] = gmt_to_localtime(data['begin_date'])
        data['end_date'] = gmt_to_localtime(data['end_date'])
        data['member'] = ','.join(data['member'])
        return data
    
    def update(self, request, *args, **kwargs):
        if request.method in ['PUT']:
            data = self.format_data(request.data)
        else:
            data = request.data
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=data, partial=partial)
        serializer.is_valid(raise_exception=False)
        if serializer.errors:
            return Response({'status':False,'data':serializer.errors})
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response({'status':True})
    
    def create(self, request, *args, **kwargs):
        data =  request.data
        data = self.format_data(data)
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=False)
        if serializer.errors:
            return Response({'status':False,'data':serializer.errors})
        self.perform_create(serializer)
        return Response({'status':True})
    
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        
        serializer = self.get_serializer(queryset, many=True)
        datas = serializer.data
        for data in datas:
            data['member'] = data['member'].split(',')
            attach_queryset = SubTaskAttach.objects.filter(task=data['id'])
            data['attach'] = [{'id':obj.id,
                               'name':obj.attach.name.split('/')[1],
                               'url':obj.attach.url} for obj in attach_queryset]
            
        return Response(datas)

class SubTaskAttachVS(viewsets.ModelViewSet):
    queryset = SubTaskAttach.objects.all()
    serializer_class = SubTaskAttachSeri
    
    def delete_file_from_disk(self,filename):
        fullname = os.path.join('media',filename)
        if os.path.isfile(fullname):
            os.remove(fullname)
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=False)
        if serializer.errors:
            return Response({'status':False,'data':serializer.errors},status=400)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=201, headers=headers)
    
    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        #从磁盘删除文件
        self.delete_file_from_disk(instance.attach.name)
        self.perform_destroy(instance)
        return Response(status=204)
    
class ProjectInfo(APIView):
    '''
    主要计算指定项目整个流程相关信息
    get 中 query_params 的key 使用type, value 支持
    1 duration == 项目总工时
    2 subtask == 子任务概要信息
    3 attach == 附件汇总
    '''
    
    def total_duration(self,instance_id):
        duration = 0
        objs = FlowInst.objects.filter(instance=instance_id)
        for obj in objs:
            print(obj.duration)
            duration = duration + obj.duration
        return duration
    
    def total_subtask(self,project_name):
        '''
        分组查询
        '''
        subtask_summary = {
            'finish': 0,
            'run': 0,
            'wait': 0
            }
        objs = SubTask.objects.values('status').annotate(counts=Count('id')).filter(project=project_name)
        for obj in objs:
            subtask_summary[obj['status']] = obj['counts']
        return subtask_summary
    
    def total_attach(self,project_name):
        '''
        1 使用project_name 找到 所有子任务
        2 在附件表中找出 在 子任务中的对象
        '''
        task_objs = SubTask.objects.filter(project=project_name)
        attach_objs = SubTaskAttach.objects.filter(task__in=task_objs)
        datas = []
        for attach in attach_objs:
            data = {
                'project_name': project_name,
                'flow_name': attach.task.flow_name,
                'task_name': attach.task.task_name,
                'subtask_title': attach.task.title,
                'member': attach.task.member.split(',')[0],
                'upload_time': attach.upload_time,
                'name': attach.attach.name.split('/')[1],
                'url': attach.attach.url
            }
            datas.append(data)
        return datas
    
    def get(self,request):
        type_dict = {
            'duration': self.total_duration,
            'subtask': self.total_subtask,
            'attach': self.total_attach
            }
        instance_id = request.query_params.get('instance')
        value = request.query_params.get('type')
        func = type_dict[value]
        data = func(instance_id)
        return Response(data)

class ProEventVS(viewsets.ModelViewSet):
    queryset = ProEvent.objects.all()
    serializer_class = ProEventSeri
    
    def get_queryset(self):
        '''
        重写get_queryset方法, 支持接收get 参数,过滤queryset
        '''
        queryset = ProEvent.objects.all().order_by('-create_time')
        query_dict = {}
        for key in self.request.query_params.keys():
            value=self.request.query_params.get(key,None)
            if value is not None:
                query_dict[key]=value

        queryset = queryset.filter(**query_dict)
        return queryset
    
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        
        serializer = self.get_serializer(queryset, many=True)
        datas = serializer.data
        for data in datas:
            attach_queryset = EventAttach.objects.filter(event=data['id'])
            data['attach'] = [{'id': obj.id,
                               'upload_time': obj.upload_time,
                               'name': obj.attach.name.split('/')[1],
                               'url': obj.attach.url} for obj in attach_queryset]
            
        return Response(datas)
    
    def create(self, request, *args, **kwargs):
        data =  request.data
        serializer = self.get_serializer(data=data)
        serializer.is_valid(raise_exception=False)
        if serializer.errors:
            return Response({'status':False,'data':serializer.errors})
        self.perform_create(serializer)
        return Response({'status':True})
    
    def update(self, request, *args, **kwargs):
        partial = kwargs.pop('partial', False)
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data, partial=partial)
        serializer.is_valid(raise_exception=False)
        if serializer.errors:
            return Response({'status':False,'data':serializer.errors})
        self.perform_update(serializer)

        if getattr(instance, '_prefetched_objects_cache', None):
            # If 'prefetch_related' has been applied to a queryset, we need to
            # forcibly invalidate the prefetch cache on the instance.
            instance._prefetched_objects_cache = {}

        return Response({'status':True})

class EventAttachVS(viewsets.ModelViewSet):
    queryset = EventAttach.objects.all()
    serializer_class = EventAttachSeri

class ProEventSearch(APIView):    
    def remove_null(self,search):
        tmp_search = {}
        for key in search.keys():
            if search[key] is None:
                continue
            if isinstance(search[key], list) or len(search[key].strip()) != 0:
                tmp_search[key] = search[key]
        return tmp_search
    
    def format_data(self,datas):
        for data in datas:
            attach_queryset = EventAttach.objects.filter(event=data['id'])
            data['attach'] = [{'id': obj.id,
                               'upload_time': obj.upload_time,
                               'name': obj.attach.name.split('/')[1],
                               'url': obj.attach.url} for obj in attach_queryset]
        return datas
    
    def search_for_ProEvent(self,key,value,proj,inst=None):
        kwargs = {
            'project': proj,
            '{}__contains'.format(key): value,
        }
        if inst:
            kwargs['id'] = inst
        
        queryset = ProEvent.objects.filter(**kwargs)
        return queryset
    
    def search_for_attach(self,key,value,proj,inst=None):
        kwargs = {
            'project': proj,
            '{}__contains'.format(key): value,
        }
        if inst:
            kwargs['event'] = inst
        
        queryset = EventAttach.objects.filter(**kwargs)
        return queryset
    
    def queryset_intersection(self,event_queryset,attach_queryset, has_event, has_attach):
        if has_attach and has_event: #表明前端搜索附件 和 事件
            queryset_dict = {}
            for e_queryset in event_queryset:
                for a_queryset in attach_queryset:
                    if e_queryset.id == a_queryset.event.id:
                        queryset_dict[e_queryset.id] = e_queryset
            serializer = ProEventSeri(queryset_dict.values(), many=True)
        elif has_event and not has_attach:
            serializer = ProEventSeri(event_queryset, many=True)
        else:
            serializer = ProEventSeri([a.event for a in attach_queryset], many=True)
        datas = self.format_data(serializer.data)
        return datas
    
    def post(self,request):
        proj_id = request.data['project']
        search = self.remove_null(request.data['search'])
        datas = []
        attach_queryset = []
        event_queryset = []
        has_attach = False
        has_event = False
        if not search:#如果没有搜索key
            event_queryset = ProEvent.objects.filter(project=proj_id)
            serializer = ProEventSeri(event_queryset, many=True)
            datas = serializer.data
            datas = self.format_data(datas)
        else:
            if search.get('attach'):
                attach_queryset = self.search_for_attach('attach', search['attach'], proj_id)
                del search['attach']
                has_attach = True
            
            for key in search.keys():
                has_event = True
                if  event_queryset:
                    '''
                    使用内容 到所有 上面查询到的结果里去比对, 这里是逐条比对，所以如果有数据
                    '''
                    kwargs = {
                        '{}__contains'.format(key): search[key]
                    }
                    event_queryset = event_queryset.filter(**kwargs)
                else:
                    event_queryset = self.search_for_ProEvent(key, search[key], proj_id)
            
            datas = self.queryset_intersection(event_queryset, attach_queryset, has_event, has_attach)
            
        return Response(datas)
        
        